package base

import (
	"runtime"
	"runtime/debug"
	"fmt"

)

func Dosafe(fn func(), exitfn func()) {
	defer exceptionStack(exitfn)
	fn()
}

func DosafeRoutine(fn func(), exitfn func()) {
	defer exceptionStack(exitfn)
	go fn()
}

func callerDebug() (str string) {
	str += "\n"
	i := 2
	for {
		pc, file, line, ok := runtime.Caller(i)
		if !ok || i > 10 {
			break
		}
		str += fmt.Sprintf("\t stack: %d %v [file: %s] [func: %s] [line: %d]\n", i-1, ok, file, runtime.FuncForPC(pc).Name(), line)
		i++
	}
	return str + "\n"
}

func exceptionStack(fn func()) {
	err := recover()
	if err != nil {
		if fn != nil {
			fn()
		}
		errstr := fmt.Sprintf("\n runtime error: %v\n traceback:\n", err)
		errstr += callerDebug()
		errstr += "\n"
		fmt.Println(errstr, string(debug.Stack()))
	}
}
